package cn.wx.sqlSession.defaults;

import cn.wx.session.Configuration;
import cn.wx.session.Mapper;
import cn.wx.sqlSession.SqlSession;
import cn.wx.utils.DataSourceUtil;
import cn.wx.utils.Executor;
import lombok.Data;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;

@Data
public class DefaultSqlSession implements SqlSession {

    private Configuration config;
    private Connection conn;
    private boolean commit = true;

    public void setConfig(Configuration config) {
        this.config = config;
    }

    public DefaultSqlSession() {}

    public DefaultSqlSession(boolean commit) {
        this.commit = commit;
    }

    public Connection getConnection() {
        conn = DataSourceUtil.getConnection(config);
        try {
            conn.setAutoCommit(commit);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return conn;
    }

    @Override
    public <T> T getMapper(Class<T> cla) {
        return (T) Proxy.newProxyInstance(cla.getClassLoader(),
                new Class[]{cla}, new MapperProxy(config.getMappers(), getConnection()));
    }

    @Override
    public void close() {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

class MapperProxy implements InvocationHandler {

    private final Map<String, Mapper> mappers;
    private final Connection conn;

    public MapperProxy(Map<String, Mapper> mappers, Connection conn) {
        this.mappers = mappers;
        this.conn = conn;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName(); // 方法名
        String className = method.getDeclaringClass().getName(); // 所在的类名
        String key = className + methodName;
        Mapper mapper = mappers.get(key);
        if (mapper == null) {
            throw new IllegalStateException("参数不合法");
        }
        return new Executor().selectList(mapper, conn);
    }
}
